﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Data;
using System.Data.Objects;
using System.Data.SqlClient;

namespace Returns
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        SalesManagerEntities _sme = new SalesManagerEntities();
        private tblMiscDef[] _rmaMiscDefs;
        private tblMiscDef[] _detailMiscDefs;
        private tblPackage _package;
        private tblRMAReturn _rmaReturn;
        private tblInventoryTransaction[] _inventoryTransactions;
        private List<tblInventoryTransactionDetail> _newDetails = new List<tblInventoryTransactionDetail>();
        private int? _debitAccountID, _creditAccountID;
        private int _newDetailID = -1;

        public MainWindow()
        {
            InitializeComponent();
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            txtPackageID.Focus();
        }

        private void txtPackageID_LostFocus(object sender, RoutedEventArgs e)
        {
            if (txtPackageID.Text.Trim() != string.Empty)
            {
                Int32 packageID;
                if (!Int32.TryParse(txtPackageID.Text, out packageID))
                {
                    MessageBox.Show("Invalid package ID");
                    return;
                }
                tblPackage package = (from c in _sme.tblPackage where c.PackageID == packageID select c).FirstOrDefault();
                if (package == null)
                {
                    MessageBox.Show("Invalid package ID");
                    return;
                }
                SelectPackage(package);
            }
        }

        private void txtOtherID_LostFocus(object sender, RoutedEventArgs e)
        {
            if (txtOtherID.Text.Trim() == string.Empty)
                return;
            Int32 idValue;
            if (!Int32.TryParse(txtOtherID.Text, out idValue))
            {
                MessageBox.Show("Invalid ID Value");
                return;
            }
            PackageSearch[] packages =
                _sme.ExecuteStoreQuery<PackageSearch>("select distinct T6.Description as SearchKeyType, T9.PackageID, T1.CustomerID, T7.OrderID," +
                    " T3.Name, T4.Address1, T4.City, T4.State, T4.PostalCode, T7.OrderDate," +
                    " T9.ShippedDate, T9.TrackingNumber, T5.ShortName as Owner\n" +
                    "from tblCustomer T1\n" +
                    "   join tblIDSearch T2 on T1.CustomerID = T2.CustomerID\n" +
                    "   join codeIDSearchKey T6 on T2.IDSearchKeyCode = T6.IDSearchKeyCode\n" +
                    "   join tblOrderHeader T7 on T1.CustomerID = T7.CustomerID\n" +
                    "   join tblInventoryTransaction T8 on T7.OrderID = T8.OrderID and T8.InventoryTransactionStatusCode <> 'X'\n" +
                    "   join tblPackage T9 on T8.PackageID = T9.PackageID\n" +
                    "   join tblPerson T3 on T9.PersonID = T3.PersonID\n" +
                    "   join tblAddress T4 on T9.AddressID = T4.AddressID\n" +
                    "   join tblOwner T5 on T9.OwnerID = T5.OwnerID\n" +
                    "where T2.IDValue = cast(@SearchKey as varchar(20))\n" +
                    "order by T3.Name", new SqlParameter[] { new SqlParameter("@SearchKey", idValue) }).ToArray();
            if (packages.Count() == 1)
            {
                SelectPackage((tblPackage)_sme.GetObjectByKey(new System.Data.EntityKey("SalesManagerEntities.tblPackage", "PackageID", packages.First().PackageID)));
                return;
            }
            if (packages.Count() == 0)
            {
                MessageBox.Show("No matching records found");
                return;
            }

            SelectPackageDialog dlg = new SelectPackageDialog(packages);
            if ((bool)dlg.ShowDialog())
            {
                SelectPackage((tblPackage)_sme.GetObjectByKey(new System.Data.EntityKey("SalesManagerEntities.tblPackage", "PackageID", dlg.PackageID)));
                return;
            }
        }

        private void txtSearchText_LostFocus(object sender, RoutedEventArgs e)
        {
            if (txtSearchText.Text.Trim() == string.Empty)
                return;

            PackageSearch[] packages =
                _sme.ExecuteStoreQuery<PackageSearch>("select distinct null as SearchKeyType, T9.PackageID, T1.CustomerID, T7.OrderID," +
                    " T3.Name, T4.Address1, T4.City, T4.State, T4.PostalCode, T7.OrderDate," +
                    " T9.ShippedDate, T9.TrackingNumber, T5.ShortName as Owner\n" +
                    "from tblCustomer T1\n" +
                    "   join ContainsTable(tblTextSearch, SearchKey, @SearchKey) as T2 on T1.CustomerID = T2.[key]\n" +
                    "   join tblOrderHeader T7 on T1.CustomerID = T7.CustomerID\n" +
                    "   join tblInventoryTransaction T8 on T7.OrderID = T8.OrderID and T8.InventoryTransactionStatusCode <> 'X'\n" +
                    "   join tblPackage T9 on T8.PackageID = T9.PackageID\n" +
                    "   join tblPerson T3 on T9.PersonID = T3.PersonID\n" +
                    "   join tblAddress T4 on T9.AddressID = T4.AddressID\n" +
                    "   join tblOwner T5 on T9.OwnerID = T5.OwnerID\n" +
                    "order by T3.Name", new SqlParameter[] { new SqlParameter("@SearchKey", txtSearchText.Text) }).ToArray();
            if (packages.Count() == 1)
            {
                SelectPackage((tblPackage)_sme.GetObjectByKey(new System.Data.EntityKey("SalesManagerEntities.tblPackage", "PackageID", packages.First().PackageID)));
                return;
            }
            if (packages.Count() == 0)
            {
                MessageBox.Show("No matching records found");
                return;
            }

            SelectPackageDialog dlg = new SelectPackageDialog(packages);
            if ((bool)dlg.ShowDialog())
            {
                SelectPackage((tblPackage)_sme.GetObjectByKey(new System.Data.EntityKey("SalesManagerEntities.tblPackage", "PackageID", dlg.PackageID)));
                return;
            }
        }

        private void SelectPackage(tblPackage package)
        {
            _package = package;

            _inventoryTransactions =
                (from c in _sme.tblInventoryTransaction.Include("InventoryTransactionDetails")
                 where c.PackageID == package.PackageID
                     && c.InventoryTransactionTypeCode == "S"
                     && c.InventoryTransactionStatusCode == "C"
                 select c).ToArray();

            if (_inventoryTransactions.Count() == 0)
            {
                MessageBox.Show("Nothing to return");
                return;
            }

            // Add the UserDefined fields.
            int ownerID = _inventoryTransactions[0].Inventory.Product.OwnerID;
            int orderID = (int)_inventoryTransactions[0].OrderID;
            _rmaMiscDefs = (from c in _sme.tblMiscDef
                    where c.TableName == "tblRMAReturn" && (c.OwnerID == ownerID || c.OwnerID == null)
                    select c).ToArray();
            _detailMiscDefs = (from c in _sme.tblMiscDef
                            where c.TableName == "tblInventoryTransactionDetail" && (c.OwnerID == ownerID || c.OwnerID == null)
                            select c).ToArray();

            tblOwner owner = (tblOwner)_sme.GetObjectByKey(new EntityKey("SalesManagerEntities.tblOwner", "OwnerID", ownerID));
            _debitAccountID = owner.InventoryAccountID;
            _creditAccountID = owner.CostOfGoodsSoldAccountID;

            foreach (tblInventoryTransaction invTrans in _inventoryTransactions)
            {
                // If the items are not individually tracked then create some dummy InventoryTransactionDetail records
                if (!invTrans.Inventory.Product.TrackIndividual)
                {
                    // The available amount to return is the shipped quantity minus the already returned quantity.
                    int count = invTrans.Qty + ((from c in _sme.tblInventoryTransaction
                                                where c.PackageID == package.PackageID
                                                   && ( c.InventoryTransactionTypeCode == "E" || c.InventoryTransactionTypeCode == "U" )
                                                   && c.InventoryID == invTrans.InventoryID
                                                   && c.InventoryTransactionStatusCode == "C"
                                                select c).Sum(s => (Int32?)s.Qty) ?? 0);
                        
                    for (int i = 0; i < (0 - count); i++)
                    {
                        tblInventoryTransactionDetail newDetail = new tblInventoryTransactionDetail();
                        newDetail.InventoryTransactionID = invTrans.InventoryTransactionID;
                        newDetail.InventoryTransactionDetailID = _newDetailID--;
                        _sme.AddTotblInventoryTransactionDetail(newDetail);
                        _newDetails.Add(newDetail);
                    }
                }
                else
                {
                    // Remove detail records from the list that have already been returned
                    tblInventoryTransactionDetail[] details = invTrans.InventoryTransactionDetails.ToArray();
                    foreach (tblInventoryTransactionDetail invDetail in details)
                    {
                        // If a return already exists for this detail then remove it from the list
                        if ( (from c in _sme.tblInventoryTransactionDetail
                                where c.InventoryTransaction.PackageID == package.PackageID
                                    && (c.InventoryTransaction.InventoryTransactionTypeCode == "E" || c.InventoryTransaction.InventoryTransactionTypeCode == "U" )
                                    && c.InventoryTransaction.InventoryTransactionStatusCode == "C"
                                    && c.InventoryTransaction.InventoryID == invTrans.InventoryID
                                    && (c.UserDefined1 ?? string.Empty) == (invDetail.UserDefined1 ?? string.Empty)
                                    && (c.UserDefined2 ?? string.Empty) == (invDetail.UserDefined2 ?? string.Empty)
                                    && (c.UserDefined3 ?? 0) == (invDetail.UserDefined3 ?? 0)
                                    && (c.UserDefined4 ?? 0) == (invDetail.UserDefined4 ?? 0)
                                select c).Count() > 0)
                            _sme.DeleteObject(invDetail);
                    }
                }
            }
            // The changes made here are for display purposes only and don't get written batk to the database.
            _sme.AcceptAllChanges();

            tblRMAReturn[] returns = (from c in _sme.tblRMAReturn
                                      where c.OrderID == orderID
                                          && c.ReceiptDate == null
                                      select c).ToArray();
            if (returns.Length == 0)
            {
                _rmaReturn = new tblRMAReturn();
                _rmaReturn.OrderID = orderID;
                _rmaReturn.IssueDate = DateTime.Now;
                var v = _sme.CreateQuery<String>("SELECT value SalesManagerModel.Store.SystemUser() from {1}");

                _rmaReturn.AgentName = v.FirstOrDefault();
                _sme.AddTotblRMAReturn(_rmaReturn);
            }
            else
            {
                _rmaReturn = returns[0];
            }
            _rmaReturn.ReceiptDate = DateTime.Now;
            _sme.SaveChanges();
            _sme.spReconcileReturnDetail(_rmaReturn.RMAReturnID);

            ((CollectionViewSource)FindResource("InventoryTransactions")).Source = _inventoryTransactions;
            this.DataContext = _rmaReturn;
            HasPackage = true;
        }

        private void gridDetails_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
        {
            if (e.Column.Header.ToString().StartsWith("UserDefined"))
            {
                IEnumerable<tblMiscDef> miscDef = _detailMiscDefs.Where(c => c.FieldNumber == Int32.Parse(e.Column.Header.ToString().Substring(11)));
                if (miscDef.Count() > 0)
                    e.Column.Header = miscDef.First().Name;
                else
                    e.Cancel = true;
            }
            else
                e.Cancel = true;
        }

        //
        // SINGLE CLICK EDITING
        //
        private void DataGridCell_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            DataGridCell cell = sender as DataGridCell;
            if (cell != null && !cell.IsEditing && !cell.IsReadOnly)
            {
                if (!cell.IsFocused)
                {
                    cell.Focus();
                }
                DataGrid dataGrid = FindVisualParent<DataGrid>(cell);
                if (dataGrid != null)
                {
                    if (dataGrid.SelectionUnit != DataGridSelectionUnit.FullRow)
                    {
                        if (!cell.IsSelected)
                            cell.IsSelected = true;
                    }
                    else
                    {
                        DataGridRow row = FindVisualParent<DataGridRow>(cell);
                        if (row != null && !row.IsSelected)
                        {
                            row.IsSelected = true;
                        }
                    }
                }
            }
        }

        static T FindVisualParent<T>(UIElement element) where T : UIElement
        {
            UIElement parent = element;
            while (parent != null)
            {
                T correctlyTyped = parent as T;
                if (correctlyTyped != null)
                {
                    return correctlyTyped;
                }

                parent = VisualTreeHelper.GetParent(parent) as UIElement;
            }
            return null;
        }

        public static readonly DependencyProperty HasPackageProperty =
            DependencyProperty.Register("HasPackage", typeof(bool), typeof(MainWindow), new PropertyMetadata(false));
        public bool HasPackage
        {
            get { return (bool)GetValue(HasPackageProperty); }
            set
            {
                SetValue(HasPackageProperty, value);
                SetValue(HasNoPackageProperty, !value);
            }
        }

        public static readonly DependencyProperty HasNoPackageProperty =
            DependencyProperty.Register("HasNoPackage", typeof(bool), typeof(MainWindow), new PropertyMetadata(true));
        public bool HasNoPackage
        {
            get { return (bool)GetValue(HasNoPackageProperty); }
        }

        private void brnLoad_Click(object sender, RoutedEventArgs e)
        {
            brnLoad.Focus();
        }

        private void Clear()
        {
            foreach (tblInventoryTransactionDetail detail in _newDetails)
                _sme.DeleteObject(detail);
            _newDetails.Clear();
            _sme.AcceptAllChanges();

            this.DataContext = null;
            ((CollectionViewSource)FindResource("InventoryTransactions")).Source = null;
            HasPackage = false;
            txtPackageID.Text = string.Empty;
            txtOtherID.Text = string.Empty;
            txtSearchText.Text = string.Empty;
            txtPackageID.Focus();
        }

        private void btnNext_Click(object sender, RoutedEventArgs e)
        {
            _sme.AcceptAllChanges();
            foreach (tblInventoryTransaction invTrans in _inventoryTransactions)
            {
                foreach (tblInventoryTransactionDetail detail in invTrans.InventoryTransactionDetails)
                {
                    if (detail.ReturnDamaged || detail.ReturnToInventory)
                    {
                        tblInventoryTransaction newTrans = new tblInventoryTransaction();
                        newTrans.PackageID = invTrans.PackageID;
                        newTrans.OrderID = invTrans.OrderID;
                        newTrans.Qty = 1;
                        newTrans.RMAReturnID = _rmaReturn.RMAReturnID;
                        newTrans.UnitCost = invTrans.UnitCost;
                        newTrans.InventoryID = invTrans.InventoryID;
                        newTrans.EffectiveDate = DateTime.Now;
                        if (detail.ReturnDamaged)
                        {
                            // Damaged returns don't affect any accounts
                            newTrans.CreditAccountID = null;
                            newTrans.DebitAccountID = null;
                            newTrans.InventoryTransactionTypeCode = "U";
                        }
                        else
                        {
                            newTrans.CreditAccountID = _creditAccountID;
                            newTrans.DebitAccountID = _debitAccountID;
                            newTrans.InventoryTransactionTypeCode = "E";
                        }
                        newTrans.InventoryTransactionStatusCode = "C";
                        _sme.AddTotblInventoryTransaction(newTrans);
                        // If the TransactionDetailID is greater than 0 then this is an individually tracked item
                        if (detail.InventoryTransactionDetailID > 0)
                        {
                            tblInventoryTransactionDetail newDetail = new tblInventoryTransactionDetail();
                            newDetail.InventoryTransaction = newTrans;
                            newDetail.UserDefined1 = detail.UserDefined1;
                            newDetail.UserDefined2 = detail.UserDefined2;
                            newDetail.UserDefined3 = detail.UserDefined3;
                            newDetail.UserDefined4 = detail.UserDefined4;
                            _sme.AddTotblInventoryTransactionDetail(newDetail);
                        }
                    }
                }
            }
            _sme.SaveChanges();
            Clear();
        }

        private void btnCancel_Click(object sender, RoutedEventArgs e)
        {
            // Remove added entities
            ObjectStateEntry[] entries = _sme.ObjectStateManager.GetObjectStateEntries(System.Data.EntityState.Added).ToArray();
            foreach (ObjectStateEntry entry in entries)
                entry.Delete();
            Clear();
        }

        private void btnExit_Click(object sender, RoutedEventArgs e)
        {
            Close();
        }

        private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            if (_sme.ObjectStateManager.GetObjectStateEntries(EntityState.Added | EntityState.Deleted | EntityState.Modified).Count() > 0)
            {
                MessageBoxResult result = MessageBox.Show("Do you want to save changes before closing?", "Save changes?", MessageBoxButton.YesNoCancel);
                if (result == MessageBoxResult.Cancel)
                    e.Cancel = true;
                if (result == MessageBoxResult.Yes)
                    _sme.SaveChanges();
            }
        }

    }
}
